<template>
  <div class="error-boundary">
    <!-- 正常内容 -->
    <template v-if="!hasError">
      <slot />
    </template>
    
    <!-- 错误状态 -->
    <template v-else>
      <div class="error-boundary__container">
        <div class="error-boundary__content">
          <!-- 错误图标 -->
          <div class="error-boundary__icon">
            <i class="el-icon-warning-outline" />
          </div>
          
          <!-- 错误信息 -->
          <div class="error-boundary__message">
            <h3 class="error-boundary__title">
              {{ errorTitle }}
            </h3>
            <p class="error-boundary__description">
              {{ errorMessage }}
            </p>
            
            <!-- 错误详情（开发环境） -->
            <details 
              v-if="showDetails && errorDetails" 
              class="error-boundary__details"
            >
              <summary>错误详情</summary>
              <pre class="error-boundary__stack">{{ errorDetails }}</pre>
            </details>
          </div>
          
          <!-- 操作按钮 -->
          <div class="error-boundary__actions">
            <button 
              class="error-boundary__button error-boundary__button--primary"
              @click="handleRetry"
              :disabled="retrying"
            >
              <i v-if="retrying" class="el-icon-loading" />
              <i v-else class="el-icon-refresh" />
              {{ retrying ? '重试中...' : '重试' }}
            </button>
            
            <button 
              v-if="showReload"
              class="error-boundary__button error-boundary__button--secondary"
              @click="handleReload"
            >
              <i class="el-icon-refresh-right" />
              刷新页面
            </button>
            
            <button 
              v-if="showReport"
              class="error-boundary__button error-boundary__button--text"
              @click="handleReport"
            >
              <i class="el-icon-warning" />
              报告问题
            </button>
          </div>
        </div>
        
        <!-- 建议操作 -->
        <div class="error-boundary__suggestions" v-if="suggestions.length > 0">
          <h4 class="error-boundary__suggestions-title">建议尝试：</h4>
          <ul class="error-boundary__suggestions-list">
            <li v-for="suggestion in suggestions" :key="suggestion">
              {{ suggestion }}
            </li>
          </ul>
        </div>
      </div>
    </template>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, onErrorCaptured, nextTick } from 'vue'
import { handleError, ErrorType, ErrorLevel } from '@/utils/errorHandler'

// Props
interface Props {
  fallbackTitle?: string
  fallbackMessage?: string
  showDetails?: boolean
  showReload?: boolean
  showReport?: boolean
  maxRetries?: number
  onError?: (error: Error, errorInfo: any) => void
  onRetry?: () => Promise<void> | void
  onReport?: (error: Error, errorInfo: any) => void
}

const props = withDefaults(defineProps<Props>(), {
  fallbackTitle: '出现了一些问题',
  fallbackMessage: '页面遇到了错误，请尝试刷新或重试',
  showDetails: process.env.NODE_ENV === 'development',
  showReload: true,
  showReport: true,
  maxRetries: 3
})

// Emits
interface Emits {
  (e: 'error', error: Error, errorInfo: any): void
  (e: 'retry'): void
  (e: 'recover'): void
}

const emit = defineEmits<Emits>()

// State
const hasError = ref(false)
const error = ref<Error | null>(null)
const errorInfo = ref<any>(null)
const retryCount = ref(0)
const retrying = ref(false)

// Computed
const errorTitle = computed(() => {
  if (!error.value) return props.fallbackTitle
  
  // 根据错误类型返回不同标题
  const message = error.value.message.toLowerCase()
  if (message.includes('network') || message.includes('fetch')) {
    return '网络连接问题'
  }
  if (message.includes('timeout')) {
    return '请求超时'
  }
  if (message.includes('auth') || message.includes('unauthorized')) {
    return '身份验证失败'
  }
  if (message.includes('permission')) {
    return '权限不足'
  }
  
  return props.fallbackTitle
})

const errorMessage = computed(() => {
  if (!error.value) return props.fallbackMessage
  
  // 根据错误类型返回友好的错误消息
  const message = error.value.message.toLowerCase()
  if (message.includes('network')) {
    return '网络连接异常，请检查网络设置后重试'
  }
  if (message.includes('timeout')) {
    return '请求超时，请稍后重试'
  }
  if (message.includes('auth') || message.includes('unauthorized')) {
    return '身份验证失败，请重新登录'
  }
  if (message.includes('permission')) {
    return '您没有权限执行此操作'
  }
  if (message.includes('not found')) {
    return '请求的资源不存在'
  }
  
  return error.value.message || props.fallbackMessage
})

const errorDetails = computed(() => {
  if (!error.value) return ''
  
  return `${error.value.name}: ${error.value.message}\n${error.value.stack || ''}`
})

const suggestions = computed(() => {
  if (!error.value) return []
  
  const message = error.value.message.toLowerCase()
  const suggestions: string[] = []
  
  if (message.includes('network')) {
    suggestions.push('检查网络连接是否正常')
    suggestions.push('尝试切换网络环境')
    suggestions.push('关闭VPN或代理软件')
  }
  
  if (message.includes('timeout')) {
    suggestions.push('稍等片刻后重试')
    suggestions.push('检查网络速度')
  }
  
  if (message.includes('auth')) {
    suggestions.push('重新登录账户')
    suggestions.push('清除浏览器缓存')
  }
  
  if (message.includes('memory') || message.includes('heap')) {
    suggestions.push('关闭其他标签页')
    suggestions.push('重启浏览器')
  }
  
  // 通用建议
  if (suggestions.length === 0) {
    suggestions.push('刷新页面重试')
    suggestions.push('清除浏览器缓存')
    suggestions.push('尝试使用其他浏览器')
  }
  
  return suggestions
})

// Methods
const captureError = (err: Error, info: any) => {
  hasError.value = true
  error.value = err
  errorInfo.value = info
  
  // 处理错误
  handleError(err, {
    component: 'ErrorBoundary',
    errorInfo: info,
    retryCount: retryCount.value
  })
  
  // 调用回调
  props.onError?.(err, info)
  emit('error', err, info)
  
  console.error('ErrorBoundary caught an error:', err, info)
}

const handleRetry = async () => {
  if (retrying.value || retryCount.value >= props.maxRetries) {
    return
  }
  
  try {
    retrying.value = true
    retryCount.value++
    
    // 调用重试回调
    if (props.onRetry) {
      await props.onRetry()
    }
    
    // 重置错误状态
    hasError.value = false
    error.value = null
    errorInfo.value = null
    
    emit('retry')
    emit('recover')
    
    // 等待下一个tick确保组件重新渲染
    await nextTick()
    
  } catch (retryError) {
    console.error('Retry failed:', retryError)
    handleError(retryError as Error, {
      action: 'retry',
      originalError: error.value,
      retryCount: retryCount.value
    })
  } finally {
    retrying.value = false
  }
}

const handleReload = () => {
  window.location.reload()
}

const handleReport = () => {
  if (error.value && errorInfo.value) {
    props.onReport?.(error.value, errorInfo.value)
    
    // 可以集成错误报告服务
    const reportData = {
      error: {
        name: error.value.name,
        message: error.value.message,
        stack: error.value.stack
      },
      errorInfo: errorInfo.value,
      userAgent: navigator.userAgent,
      url: window.location.href,
      timestamp: new Date().toISOString(),
      retryCount: retryCount.value
    }
    
    console.log('Error report:', reportData)
    
    // 这里可以发送到错误监控服务
    // 例如：Sentry.captureException(error.value, { extra: reportData })
  }
}

const reset = () => {
  hasError.value = false
  error.value = null
  errorInfo.value = null
  retryCount.value = 0
  retrying.value = false
}

// Error capture
onErrorCaptured((err: Error, instance, info: string) => {
  captureError(err, {
    componentName: instance?.$options.name || 'Unknown',
    errorInfo: info,
    props: instance?.$props
  })
  
  // 返回 false 阻止错误继续向上传播
  return false
})

// Expose methods
defineExpose({
  reset,
  retry: handleRetry,
  hasError: computed(() => hasError.value),
  error: computed(() => error.value),
  retryCount: computed(() => retryCount.value)
})
</script>

<style lang="scss" scoped>
.error-boundary {
  width: 100%;
  height: 100%;
}

.error-boundary__container {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 300px;
  padding: 40px 20px;
  text-align: center;
}

.error-boundary__content {
  max-width: 500px;
  width: 100%;
}

.error-boundary__icon {
  font-size: 64px;
  color: #f56c6c;
  margin-bottom: 24px;
}

.error-boundary__message {
  margin-bottom: 32px;
}

.error-boundary__title {
  font-size: 24px;
  font-weight: 600;
  color: #303133;
  margin: 0 0 12px 0;
}

.error-boundary__description {
  font-size: 16px;
  color: #606266;
  line-height: 1.5;
  margin: 0 0 16px 0;
}

.error-boundary__details {
  text-align: left;
  margin-top: 16px;
  
  summary {
    cursor: pointer;
    font-weight: 600;
    color: #909399;
    margin-bottom: 8px;
    
    &:hover {
      color: #606266;
    }
  }
}

.error-boundary__stack {
  background: #f5f7fa;
  border: 1px solid #e4e7ed;
  border-radius: 4px;
  padding: 12px;
  font-size: 12px;
  color: #606266;
  overflow-x: auto;
  white-space: pre-wrap;
  word-break: break-all;
}

.error-boundary__actions {
  display: flex;
  justify-content: center;
  gap: 12px;
  flex-wrap: wrap;
}

.error-boundary__button {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 10px 20px;
  border: none;
  border-radius: 6px;
  font-size: 14px;
  cursor: pointer;
  transition: all 0.2s;
  
  &:disabled {
    opacity: 0.6;
    cursor: not-allowed;
  }
  
  &--primary {
    background: #409eff;
    color: #fff;
    
    &:hover:not(:disabled) {
      background: #337ecc;
    }
  }
  
  &--secondary {
    background: #f5f7fa;
    color: #606266;
    border: 1px solid #dcdfe6;
    
    &:hover:not(:disabled) {
      background: #e4e7ed;
      border-color: #c0c4cc;
    }
  }
  
  &--text {
    background: transparent;
    color: #909399;
    
    &:hover:not(:disabled) {
      color: #606266;
    }
  }
  
  .el-icon-loading {
    animation: spin 1s linear infinite;
  }
}

.error-boundary__suggestions {
  margin-top: 32px;
  text-align: left;
  max-width: 400px;
  width: 100%;
}

.error-boundary__suggestions-title {
  font-size: 16px;
  font-weight: 600;
  color: #303133;
  margin: 0 0 12px 0;
}

.error-boundary__suggestions-list {
  list-style: none;
  padding: 0;
  margin: 0;
  
  li {
    position: relative;
    padding: 4px 0 4px 20px;
    color: #606266;
    font-size: 14px;
    line-height: 1.5;
    
    &::before {
      content: '•';
      position: absolute;
      left: 0;
      color: #909399;
    }
  }
}

@keyframes spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

// 移动端优化
@media (max-width: 768px) {
  .error-boundary__container {
    padding: 20px 16px;
    min-height: 250px;
  }
  
  .error-boundary__icon {
    font-size: 48px;
    margin-bottom: 20px;
  }
  
  .error-boundary__title {
    font-size: 20px;
  }
  
  .error-boundary__description {
    font-size: 14px;
  }
  
  .error-boundary__actions {
    flex-direction: column;
    align-items: center;
    gap: 8px;
  }
  
  .error-boundary__button {
    width: 100%;
    max-width: 200px;
    justify-content: center;
  }
  
  .error-boundary__suggestions {
    margin-top: 24px;
  }
  
  .error-boundary__suggestions-title {
    font-size: 14px;
  }
  
  .error-boundary__suggestions-list li {
    font-size: 13px;
  }
}
</style>